﻿using System;
using System.Collections.Generic;

namespace Keyki.NefClass.Kernel.Data
{
	/// <summary>
	/// DataSet class
	/// </summary>
	public sealed class DataSet
	{
		private readonly List<Feature> features;
		private readonly List<int> indexes;
		private readonly Species species;

		public DataSet()
		{
			features = new List<Feature>();
			indexes = new List<int>();
			species = new Species();
		}//Dataset

		/// <summary>
		/// Return Species by index
		/// </summary>
		/// <param name="index">index of dataSample</param>
		/// <returns></returns>
		public int this[int index]
		{
			get
			{
				if (indexes == null)
					throw new NullReferenceException("Species is null");

				if (features == null)
					throw new NullReferenceException("Features is null");

				if (indexes.Count < index)
					throw new ArgumentOutOfRangeException();

				return indexes[index];
			} //get
			set
			{
				if (indexes == null)
					throw new NullReferenceException("Species is null");

				if (features == null)
					throw new NullReferenceException("Features is null");

				if (indexes.Count < index)
					throw new ArgumentOutOfRangeException();

				indexes[index] = value;
			} //set
		}

		//this[index]

		/// <summary>
		/// return number of features
		/// </summary>
		public int Count
		{
			get { return features.Count; }
		}//Count

		/// <summary>
		/// return number of classes
		/// </summary>
		public int CountClasses
		{
			get { return species.Count; }
		}

		/// <summary>
		/// Return DataRow by it index
		/// </summary>
		/// <param name="index">index of row</param>
		/// <returns>DataRow</returns>
		public DataSample DataRow(int index)
		{
			var dataSample = new DataSample(features.Count);

			foreach (Feature feature in features)
			{
				dataSample.Add(feature[index]);
			} //foreach

			return dataSample;
		}//DataSample

		/// <summary>
		/// Add new feature to list
		/// </summary>
		/// <param name="feature"></param>
		public void Add(Feature feature)
		{
			features.Add(feature);
		}

		//Add

		/// <summary>
		/// Add new row to dataSet
		/// </summary>
		/// <param name="values">dataRow</param>
		/// <param name="id">Class id</param>
		public void Add(List<double> values, int id)
		{
			if (species.Count <= id)
				throw new IndexOutOfRangeException();

			if (features.Count != values.Count)
				throw new ArgumentOutOfRangeException();

			for (int i = 0; i < features.Count; i++)
			{
				features[i].Add(values[i]);
			} //for

			indexes.Add(id);
		}//Add()

		/// <summary>
		/// Add new row to dataSet
		/// </summary>
		/// <param name="values">dataRow</param>
		/// <param name="name">Class name</param>
		public void Add(List<double> values, String name)
		{
			Add(values, species.IndexOf(name));
		}//Add()

		/// <summary>
		/// Add new Specie to Species list
		/// </summary>
		/// <param name="name">name for new specie</param>
		public void Add(string name)
		{
			species.Add(name);
		}//Add

		/// <summary>
		/// Remove row from dataset with specified index
		/// </summary>
		/// <param name="index">index of row which must be removed</param>
		public void Remove(int index)
		{
			foreach (Feature feature in features)
			{
				feature.Remove(index);
			} //foreach

			indexes.RemoveAt(index);
		}//Remove()

		/// <summary>
		/// Remove item from species list
		/// </summary>
		/// <param name="name">name of specie which must be removed</param>
		public void Remove(string name)
		{
			species.Remove(name);
		}//Remove

		/// <summary>
		/// Return Feature from features list by it index
		/// </summary>
		/// <param name="id">index of feature to return</param>
		/// <returns>feature</returns>
		public Feature GetAt(int id)
		{
			if (features.Count < id)
				throw new ArgumentOutOfRangeException();

			return features[id];
		}//GetAt

		/// <summary>
		/// Return class name
		/// </summary>
		/// <param name="id">id of class</param>
		/// <returns>class name</returns>
		public string GetName(int id)
		{
			return species[id];
		}//GetName

	}//Dataset
}//Keyki.NefClass.Kernel.Classes